/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = jolt_core.c                                        */
/*  NOTE      =                                                    */
/*  DATE      = 2015/06/02 by songbb                               */
/*******************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>

#include "frcomm.h"
#include "frstr.h"
#include "frhash2.h"
#include "frmem.h"
#include "frlog.h"
#include "frsutl.h"
#include "frreport_comm.h"
#include "frservice_comm.h"

#include "conntrack.h"
#include "frct_comm.h"
#include "frversion.h"

#include "jolt_comm.h"
#include "jolt_core.h"
#include "jolt_header.h"
#include "jolt_packet.h"
#include "jolt_dataxfer.h"
#include "config.h"

extern void *g_p_apm_context;

/*******************************************************************************
*  FUNC     :  Jolt Session初始化
*  ARGS     :  *p_st_session                            (L7层session信息)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __jolt_private_session_init(L7_session *p_st_session)
{
    JOLT_PRINT_INFO("session init\n");
    L7session_jolt_private *p_st_jolt_private = NULL;      // Jolt的私有信息
    L7session_jolt *p_st_jolt_sess = NULL;                 // Jolt的私有session信息
    L7_jolt_packet *p_st_jolt_packet = NULL;               // Jolt格式的packet包
    L7_jolt_stmt *p_st_jolt_stmt = NULL;                   // Jolt消息指令

    // 1. 初始化Jolt的私有session信息
    if ((p_st_jolt_sess = (L7session_jolt *) frmalloc(sizeof(L7session_jolt))) == NULL)
    {
        JOLT_MALLOCK_ERR;
        goto error;
    }
    memset(p_st_jolt_sess, 0x00, sizeof(L7session_jolt));
    p_st_jolt_sess->i_jolti18nflag = APM_JOLT_FLAG_UNSET;
    p_st_jolt_sess->i_utf8fix = FR_NO;
    p_st_jolt_sess->i_utf8all = FR_NO;

    // 2. 初始化Jolt格式的packet包
    if ((p_st_jolt_packet = (L7_jolt_packet *) frmalloc(sizeof(L7_jolt_packet))) == NULL)
    {
        JOLT_MALLOCK_ERR;
        goto error;
    }
    memset(p_st_jolt_packet, 0x00, sizeof(L7_jolt_packet));
    if (jolt_init_packet(p_st_jolt_packet) != FR_SUCC)
        goto error;

    // 3. 初始化Jolt消息指令
    if ((p_st_jolt_stmt = (L7_jolt_stmt *) frmalloc(sizeof(L7_jolt_stmt))) == NULL)
    {
        JOLT_MALLOCK_ERR;
        goto error;
    }
    memset(p_st_jolt_stmt, 0x00, sizeof(L7_jolt_stmt));
    p_st_jolt_stmt->p_list_msg_data = frlist_create();

    // 4. 创建和初始化Jolt的私有信息
    if ((p_st_jolt_private = (L7session_jolt_private *) frmalloc(sizeof(L7session_jolt_private))) == NULL)
    {
        JOLT_MALLOCK_ERR;
        goto error;
    }
    memset(p_st_jolt_private, 0x00, sizeof(L7session_jolt_private));
    p_st_jolt_private->p_st_sess = p_st_jolt_sess;
    p_st_jolt_private->p_st_jolt_packet = p_st_jolt_packet;
    p_st_jolt_private->p_st_session = p_st_session;
    p_st_jolt_private->p_st_jolt_stmt = p_st_jolt_stmt;

    // 5. 设置L7_session的p_session_private信息
    frct_set_session_private(p_st_session, (void *)p_st_jolt_private);

    return FR_SUCC;
error:
    jolt_free((void **) &p_st_jolt_sess);
    if (p_st_jolt_packet != NULL)
    {
        bytebuff_free(&(p_st_jolt_packet->p_st_packet));
        jolt_free((void **) &p_st_jolt_packet);
    }
    jolt_free_stmt(&p_st_jolt_stmt);
    jolt_free((void **) &p_st_jolt_private);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  分析数据方向
*  ARGS     :  ui_msgcode                               (MsgCode)
*  RTN      :  0x00                                     (FR_DIRECT_UNKNOWN)
*              0x02                                     (FR_DIRECT_SRV2CLIENT)
*              0x03                                     (FR_DIRECT_CLIENT2SRV)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __jolt_analyze_direct(unsigned int ui_msgcode)
{
    switch (ui_msgcode)
    {
        case APM_JOLT_MSGCODE_CHECKAUTH:
        case APM_JOLT_MSGCODE_DH:
        case APM_JOLT_MSGCODE_ESTCON:
        case APM_JOLT_MSGCODE_CHALLENGE:
        case APM_JOLT_MSGCODE_TICKET:
        case APM_JOLT_MSGCODE_RECONNECT:
        case APM_JOLT_MSGCODE_DATAXFER:
        case APM_JOLT_MSGCODE_CLOSE:
            return FR_DIRECT_CLIENT2SRV;
        case APM_JOLT_MSGCODE_CHECKAUTH + APM_JOLT_MSGCODE_REPLY:
        case APM_JOLT_MSGCODE_DH + APM_JOLT_MSGCODE_REPLY:
        case APM_JOLT_MSGCODE_ESTCON + APM_JOLT_MSGCODE_REPLY:
        case APM_JOLT_MSGCODE_CHALLENGE + APM_JOLT_MSGCODE_REPLY:
        case APM_JOLT_MSGCODE_TICKET + APM_JOLT_MSGCODE_REPLY:
        case APM_JOLT_MSGCODE_RECONNECT + APM_JOLT_MSGCODE_REPLY:
        case APM_JOLT_MSGCODE_DATAXFER + APM_JOLT_MSGCODE_REPLY:
        case APM_JOLT_MSGCODE_CLOSE + APM_JOLT_MSGCODE_REPLY:
            return FR_DIRECT_SRV2CLIENT;
        default:
            return FR_DIRECT_UNKNOWN;
    }
}

/*******************************************************************************
*  FUNC     :  判断当前数据链路是否是Jolt协议的
*  ARGS     :  *p_st_conn                           (ct信息)
*           :  *p_st_data_in                        (协议分析入力数据)
*  RTN      :  参照module.h中APM_L7_IS_的定义
*  NOTE     :
*******************************************************************************/
int jolt_detect(Conntrack *p_st_conn
              , Apm_packet *p_st_packet)
{
    JOLT_PRINT_INFO("jolt_detect\n");
    int i_analyzed_direct = 0;
    Jolt_header st_jolt_header;

    if(p_st_conn == NULL || p_st_packet==NULL)
        return APM_L7_IS_UNKNOWN;

    memset(&st_jolt_header, 0x00, sizeof(st_jolt_header));

#if APM_JOLT_DBG
    char arr_ip_src[56], arr_ip_dst[56];
    snprintf(arr_ip_src, sizeof(arr_ip_src), "%s", int_ntoa(p_st_packet->src_ip));
    snprintf(arr_ip_dst, sizeof(arr_ip_src), "%s", int_ntoa(p_st_packet->dst_ip));
    JOLT_PRINT_TIMEVAL("PacketIn", p_st_packet->st_timestamp);
    JOLT_PRINT_DBG("Src:[%s:%d] Dest:[%s:%d] Length:[%u]\n", arr_ip_src, p_st_packet->src_port, arr_ip_dst, p_st_packet->dst_port, p_st_packet->ui_payload_len);
#endif

    int i_ret = jolt_header_detect(p_st_packet->p_payload, p_st_packet->ui_payload_len);
    if (i_ret != APM_L7_IS_YES && p_st_packet->ui_payload_len != 0) //使用协议判断不成功时，使用保存的服务器信息进行判断
    {
        if (p_st_packet->i_direction == FR_DIRECT_UNKNOWN || frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
        {
            if (frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL) == FR_SUCC)
            {
                JOLT_PRINT_ALERT("frservice_get success:[%s:%d]\n", arr_ip_dst, p_st_packet->dst_port);
                if (frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port) != FR_SUCC)
                    return APM_L7_IS_UNKNOWN;
                i_ret = APM_L7_IS_YES;
            }
            else if (frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0, NULL) == FR_SUCC)
            {
                JOLT_PRINT_ALERT("frservice_get success:[%s:%d]\n", arr_ip_src, p_st_packet->src_port);
                if (frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port) != FR_SUCC)
                    return APM_L7_IS_UNKNOWN;
                i_ret = APM_L7_IS_YES;
            }
        }
        else
        {
            if (frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL) == FR_SUCC)
            {
                JOLT_PRINT_ALERT("frservice_get success:[%s:%d]\n", arr_ip_dst, p_st_packet->dst_port);
                if (frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port) != FR_SUCC)
                    return APM_L7_IS_UNKNOWN;
                i_ret = APM_L7_IS_YES;
            }
        }
    }
    if (i_ret == APM_L7_IS_YES)
    {
        // 设置方向
        if (p_st_packet->i_direction == FR_DIRECT_UNKNOWN || frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
        {
            if (jolt_header_unpack(p_st_packet->p_payload, p_st_packet->ui_payload_len, &st_jolt_header) != FR_SUCC)
                return APM_L7_IS_UNKNOWN;
            i_analyzed_direct = __jolt_analyze_direct(st_jolt_header.ui_msgcode);
            if (i_analyzed_direct == FR_DIRECT_CLIENT2SRV)
            {
                if (frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port) != FR_SUCC)
                    return APM_L7_IS_UNKNOWN;
            }
            else if (i_analyzed_direct == FR_DIRECT_SRV2CLIENT)
            {
                if (frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port) != FR_SUCC)
                    return APM_L7_IS_UNKNOWN;
            }
            else
            {
                JOLT_PRINT_EMERG("Can not analyze direction\n");
                return APM_L7_IS_UNKNOWN;
            }
        }
    }

    if (i_ret == APM_L7_IS_UNKNOWN)
        JOLT_PRINT_ERR("detect unknown\n\n");
    else
        JOLT_PRINT_ERR("detect yes\n\n");

    return i_ret;
}

/*******************************************************************************
*  FUNC     :  Jolt协议解析
*  ARGS     :  *p_st_conn                           (ct信息)
*           :  *p_st_packet                        (协议分析入力数据)
*           :  *p_st_hash_report                    (保存Frreport_data)
*  RTN      :  参照module.h中APM_L7_ANALYZE_的定义
*  NOTE     :
*******************************************************************************/
int jolt_analyze(Conntrack *p_st_conn
               , Apm_packet *p_st_packet
               , Frhash_header *p_st_hash_report)
{
    JOLT_PRINT_INFO("jolt_analyze\n");
    L7_session *p_st_session = frct_get_session(p_st_conn);
    L7session_jolt_private *p_st_session_private = NULL;
    L7session_jolt *p_st_sess = NULL;
    L7_jolt_packet *p_st_jolt_packet = NULL;
    int i_unfragmented_ret = 0;
    int i_analyze_ret = 0;                  // 本函数的返回值
    char arr_ip_src[56], arr_ip_dst[56];

    if(p_st_conn == NULL || p_st_packet == NULL || p_st_hash_report == NULL )
        return APM_L7_ANALYZE_FAIL;

    snprintf(arr_ip_src, sizeof(arr_ip_src), "%s", int_ntoa(p_st_packet->src_ip));
    snprintf(arr_ip_dst, sizeof(arr_ip_src), "%s", int_ntoa(p_st_packet->dst_ip));

    JOLT_PRINT_TIMEVAL("PacketIn", p_st_packet->st_timestamp);
    JOLT_PRINT_DBG("Src:[%s:%d] Dest:[%s:%d] SessionID:[%s]\n", arr_ip_src, p_st_packet->src_port, arr_ip_dst, p_st_packet->dst_port, p_st_session->arr_session_id);

    /*
    * 如果入力p_st_data_in是FIN包, 说明本次connection结束,
    * 释放本次session信息. 如果入力p_st_data_in是SYN包,说明新的
    * connection开始了, 释放上次可能残留的session信息
    */
    if (p_st_packet->em_analyz_cmd == FRANALYZ_CMD_FIN || p_st_packet->em_analyz_cmd == FRANALYZ_CMD_SYN)
    {
        if (p_st_packet->em_analyz_cmd == FRANALYZ_CMD_SYN)
            JOLT_PRINT_INFO("SYN PACKET\n");
        else if (p_st_packet->em_analyz_cmd == FRANALYZ_CMD_FIN)
            JOLT_PRINT_INFO("FIN PACKET\n");
        if (p_st_session->p_session_private != NULL)
        {
            jolt_session_destory(p_st_session->p_session_private);
            p_st_session->p_session_private = NULL;
        }
        JOLT_PRINT("### i_analyze_ret:[%d]\n\n", APM_L7_ANALYZE_SUCC);
        return APM_L7_ANALYZE_SUCC;
    }

    // 本次链路的第一个有效packet包,创建链路
    if (p_st_session->p_session_private == NULL)
    {
        // 初始化Jolt的session数据
        if (__jolt_private_session_init(p_st_session) != FR_SUCC)
            goto jolt_analyze_fail;

        // 设置session uuid
        fruuid(p_st_session->arr_session_id);
    }

    // 打印方向
    switch (p_st_packet->i_direction)
    {
        case FR_DIRECT_CLIENT2SRV:
            JOLT_PRINT("client["KLIMEGREEN"%s:%d"RESET"] to server["KLIMEGREEN"%s:%d"RESET"] ["KYELLOW"%d"RESET"] ->>>>>>>>>>>>>>>>>>>>>>>\n",
                      arr_ip_src,
                      p_st_packet->src_port,
                      arr_ip_dst,
                      p_st_packet->dst_port,
                      p_st_packet->ui_payload_len);
            frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0);
            JOLT_PRINT_ALERT("frservice_add:[%s:%d]\n", arr_ip_dst, p_st_packet->dst_port);
            break;
        case FR_DIRECT_SRV2CLIENT:
            JOLT_PRINT("server["KLIMEGREEN"%s:%d"RESET"] to client["KLIMEGREEN"%s:%d"RESET"] ["KYELLOW"%d"RESET"] <<<<<<<<<<<<<<<<<<<<<<<-\n",
                      arr_ip_src,
                      p_st_packet->src_port,
                      arr_ip_dst,
                      p_st_packet->dst_port,
                      p_st_packet->ui_payload_len);
            frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0);
            JOLT_PRINT_ALERT("frservice_add:[%s:%d]\n", arr_ip_src, p_st_packet->src_port);
            break;
        default:
            JOLT_PRINT("unknown direction, src["KLIMEGREEN"%s:%d"RESET"], dest["KLIMEGREEN"%s:%d"RESET"]\n",
                      arr_ip_src,
                      p_st_packet->src_port,
                      arr_ip_dst,
                      p_st_packet->dst_port);
            goto jolt_analyze_fail;
    }

    p_st_session_private = (L7session_jolt_private *) frct_get_session_private(p_st_session);
    p_st_sess = p_st_session_private->p_st_sess;
    p_st_jolt_packet = p_st_session_private->p_st_jolt_packet;

    i_unfragmented_ret = jolt_packet_unfragment(p_st_sess, p_st_packet, p_st_jolt_packet);
    if (i_unfragmented_ret == APM_JOLT_CHECK_FRAGMENT_NEED_NEXT_PACKET)
        goto jolt_analyze_todo;
    else if (i_unfragmented_ret == APM_JOLT_CHECK_FRAGMENT_ERROR)
        goto jolt_analyze_fail;

    switch (p_st_jolt_packet->ui_msgcode)
    {
        case APM_JOLT_MSGCODE_CHECKAUTH:
            JOLT_PRINT_INFO("checkauth request\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            goto jolt_analyze_success;

        case APM_JOLT_MSGCODE_CHECKAUTH + APM_JOLT_MSGCODE_REPLY:
            JOLT_PRINT_INFO("checkauth response\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            goto jolt_analyze_success;

        case APM_JOLT_MSGCODE_DH:
            JOLT_PRINT_INFO("dh request\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
            goto jolt_analyze_success;

        case APM_JOLT_MSGCODE_DH + APM_JOLT_MSGCODE_REPLY:
            JOLT_PRINT_INFO("dh response\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            goto jolt_analyze_success;

        case APM_JOLT_MSGCODE_ESTCON:
            JOLT_PRINT_INFO("estcon request\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
            goto jolt_analyze_success;

        case APM_JOLT_MSGCODE_ESTCON + APM_JOLT_MSGCODE_REPLY:
            JOLT_PRINT_INFO("estcon response\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            goto jolt_analyze_success;

        case APM_JOLT_MSGCODE_CHALLENGE:
            JOLT_PRINT_INFO("challenge request\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
            goto jolt_analyze_success;

        case APM_JOLT_MSGCODE_CHALLENGE + APM_JOLT_MSGCODE_REPLY:
            JOLT_PRINT_INFO("challenge response\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            goto jolt_analyze_success;

        case APM_JOLT_MSGCODE_TICKET:
            JOLT_PRINT_INFO("ticket request\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
            goto jolt_analyze_success;

        case APM_JOLT_MSGCODE_TICKET + APM_JOLT_MSGCODE_REPLY:
            JOLT_PRINT_INFO("ticket response\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            goto jolt_analyze_success;

        case APM_JOLT_MSGCODE_RECONNECT:
            JOLT_PRINT_INFO("reconnect request\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
            goto jolt_analyze_success;

        case APM_JOLT_MSGCODE_RECONNECT + APM_JOLT_MSGCODE_REPLY:
            JOLT_PRINT_INFO("reconnect response\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            goto jolt_analyze_success;

        case APM_JOLT_MSGCODE_DATAXFER:
            JOLT_PRINT_INFO("dataxfer request\n");
            if (p_st_jolt_packet->ui_uncmprsz > 0 && jolt_packet_inflater(p_st_jolt_packet) != FR_SUCC)
            {
                JOLT_PRINT_CRIT("inflater error!\n");
                goto jolt_analyze_fail;
            }
            if (jolt_dataxfer_req(p_st_conn, p_st_sess, p_st_jolt_packet, p_st_hash_report) == FR_SUCC)
            {
                i_analyze_ret = APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
                goto jolt_analyze_success;
            }
            goto jolt_analyze_fail;

        case APM_JOLT_MSGCODE_DATAXFER + APM_JOLT_MSGCODE_REPLY:
            JOLT_PRINT_INFO("dataxfer response\n");
            if (p_st_jolt_packet->ui_uncmprsz > 0 && jolt_packet_inflater(p_st_jolt_packet) != FR_SUCC)
            {
                JOLT_PRINT_CRIT("inflater error!\n");
                goto jolt_analyze_fail;
            }
            if (jolt_dataxfer_resp(p_st_conn, p_st_sess, p_st_jolt_packet, p_st_hash_report) == FR_SUCC)
            {
                i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
                goto jolt_analyze_success;
            }
            goto jolt_analyze_fail;

        case APM_JOLT_MSGCODE_CLOSE:
            JOLT_PRINT_INFO("close request\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
            goto jolt_analyze_success;

        case APM_JOLT_MSGCODE_CLOSE + APM_JOLT_MSGCODE_REPLY:
            JOLT_PRINT_INFO("close response\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            goto jolt_analyze_success;

        default:
            JOLT_PRINT_EMERG("invalid msg code:[%d]\n", p_st_jolt_packet->ui_msgcode);
            JOLT_FRLOG_ERROR("invalid msg code:[%d]", p_st_jolt_packet->ui_msgcode);
            goto jolt_analyze_fail;
    }

jolt_analyze_todo:
    JOLT_PRINT("### i_analyze_ret todo:[%d]\n\n", APM_L7_ANALYZE_TODO);
    return APM_L7_ANALYZE_TODO;

jolt_analyze_success:
    JOLT_PRINT("### i_analyze_ret success:[%d]\n\n", i_analyze_ret);
    return i_analyze_ret;

jolt_analyze_fail:
    if (jolt_packet_is_in_fragment(p_st_jolt_packet))
    {
        if (bytebuff_setPosition(p_st_jolt_packet->p_st_packet, 0) != FR_SUCC)
        {
            p_st_jolt_packet->fragment_state = APM_JOLT_FRAGMENT_INIT;
            return APM_L7_ANALYZE_FAIL;
        }
        goto jolt_analyze_todo;
    }
    else
    {
        JOLT_PRINT_PACKET("error packet", p_st_jolt_packet);
        jolt_init_packet(p_st_jolt_packet);
    }

    JOLT_PRINT_EMERG("### i_analyze_ret fail:[%d]\n\n", APM_L7_ANALYZE_FAIL);
    return APM_L7_ANALYZE_FAIL;
}

/*******************************************************************************
*  FUNC     :  释放 L7session_jolt
*  ARGS     :  **pp_st_session              (L7session_jolt)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __jolt_destroy_session(L7session_jolt **pp_st_session)
{
    if (pp_st_session == NULL || *pp_st_session == NULL)
        return;

    L7session_jolt *p_st_sess = *pp_st_session;
    jolt_free((void **) &(p_st_sess->p_username));
    jolt_free((void **) &(p_st_sess->p_userrole));
    jolt_free((void **) &(p_st_sess->p_mbencoding));
    jolt_free((void **) pp_st_session);
    return;
}

/*******************************************************************************
*  FUNC     :  释放 L7_jolt_packet
*  ARGS     :  **pp_st_jolt_packet              (L7_jolt_packet)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __jolt_destroy_packet(L7_jolt_packet **pp_st_jolt_packet)
{
    if (pp_st_jolt_packet == NULL || *pp_st_jolt_packet == NULL)
        return;

    L7_jolt_packet *p_st_jolt_packet = *pp_st_jolt_packet;
    bytebuff_free(&(p_st_jolt_packet->p_st_packet));
    jolt_free((void **) pp_st_jolt_packet);
    return;
}

/*******************************************************************************
*  FUNC     :  释放 L7_jolt_stmt
*  ARGS     :  **pp_st_jolt_stmt              (L7_jolt_stmt)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __jolt_destroy_stmt(L7_jolt_stmt **pp_st_jolt_stmt)
{
    return jolt_free_stmt(pp_st_jolt_stmt);
}

/*******************************************************************************
*  FUNC     :  释放Jolt private数据
*  ARGS     :  *p_st_session_private_in                 (Jolt的私有信息)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int jolt_session_destory(void *p_st_session_private_in)
{
    JOLT_PRINT(KBLUE "\njolt_session_destory run\n" RESET);
    if (p_st_session_private_in == NULL)
        return FR_SUCC;

    L7session_jolt_private *p_st_private = (L7session_jolt_private *) p_st_session_private_in;

    __jolt_destroy_session(&(p_st_private->p_st_sess));

    __jolt_destroy_packet(&(p_st_private->p_st_jolt_packet));

    __jolt_destroy_stmt(&(p_st_private->p_st_jolt_stmt));

    frreport_body_l7list_free(&(p_st_private->p_report_comm));
    frreport_body_l7list_free(&(p_st_private->p_report_req));

    jolt_free((void **) &p_st_private);

    JOLT_PRINT_INFO("leave jolt_session_destory\n");
    return FR_SUCC;
}
